home *** CD-ROM | disk | FTP | other *** search
- #include <unistd.h>
- #include <stdlib.h>
- #include <pwd.h>
- #include <sys/stat.h>
- #include "../xconf/xconf.h"
- #include "../paths.h"
- #include "internal.h"
- #include "userconf.h"
- #include "userconf.m"
-
- /* #Specification: userconf / etc/passwd
- /etc/passwd is the user database. Its permission flags are
- always set to 0644 when rewritten.
- */
- #define ETC_PTMP "/etc/ptmp"
- static USERCONF_HELP_FILE help_users ("users");
- static CONFIG_FILE f_passwd (ETC_PASSWD,help_users,CONFIGF_MANAGED
- ,"root","root",0644);
-
- PUBLIC USERS::USERS()
- {
- /* #Specification: /etc/passwd / strategy
- /etc/passwd is read "by hand" instead of using getpwent() to avoid
- getting all those NIS entries. This is done when editing local
- user account.
- */
- FILE *fin = f_passwd.fopen ("r");
- if (fin != NULL){
- char line[1000];
- while (fgets(line,sizeof(line)-1,fin)!=NULL){
- strip_end (line);
- if (line[0] != '\0'){
- add (new USER(line));
- }
- }
- fclose (fin);
- }
- shadows = NULL;
- if (shadow_exist()) shadows = new SHADOWS;
- rstmodified();
- }
-
- PUBLIC USERS::~USERS()
- {
- delete shadows;
- }
- /*
- Get one USER specification of the table or NULL
- */
- PUBLIC USER *USERS::getitem(int no)
- {
- return (USER*)ARRAY::getitem(no);
- }
- /*
- Get one USER specification of the table or NULL from his login name
- */
- PUBLIC USER *USERS::getitem(const char *name)
- {
- USER *ret = NULL;
- int nbu = getnb();
- for (int i=0; i<nbu; i++){
- USER *usr = getitem(i);
- if (strcmp(usr->getname(),name)==0){
- ret = usr;
- break;
- }
- }
- return ret;
- }
- /*
- Get one SHADOW specification of the table or NULL from his login name
- */
- PUBLIC SHADOW *USERS::getshadow(USER *usr)
- {
- SHADOW *ret = NULL;
- if (shadows != NULL) ret = shadows->getitem(usr->getname());
- return ret;
- }
- PUBLIC void USERS::addshadow (SHADOW *shadow)
- {
- shadows->add (shadow);
- }
- /*
- Get one USER specification of the table or NULL from his UID
- */
- PUBLIC USER *USERS::getfromuid(int uid)
- {
- USER *ret = NULL;
- int nbu = getnb();
- for (int i=0; i<nbu; i++){
- USER *usr = getitem(i);
- if (usr->getuid() == uid){
- ret = usr;
- break;
- }
- }
- return ret;
- }
- /*
- Get one unused User ID base of the group name.
- This function try to organise user id group wize, allocating 500
- entry per group.
- */
- PUBLIC int USERS::getnewuid(int gid)
- {
- /* #Specification: userconf / automatic allocaion of uid
- We multiply gid by 500. From there we search in all
- user id and allocate the first uid in the range.
-
- We don't allocate into holes (unused uid between used one)
- to avoid uid reuse (and a security hole).
- */
- int base = gid * 500;
- int maxu = base + 500;
- int ret = base;
- int nbu = getnb();
- for (int i=0; i<nbu; i++){
- USER *usr = getitem(i);
- int uid = usr->getuid();
- if (uid >= base && uid < maxu){
- if (uid >= ret) ret = uid + 1;
- }
- }
- return ret;
- }
- /*
- Write the /etc/passwd file with proper locking
- */
- PUBLIC int USERS::write()
- {
- int ret = -1;
- sortbygid();
- FILE *fout = f_passwd.fopen (ETC_PTMP,"w");
- if (fout != NULL){
- int nbu = getnb();
- for (int i=0; i<nbu; i++){
- getitem(i)->write(fout);
- }
- fclose(fout);
- unlink(ETC_PASSWD ".OLD");
- link(ETC_PASSWD, ETC_PASSWD ".OLD");
- unlink(ETC_PASSWD);
- link(ETC_PTMP, ETC_PASSWD);
- unlink(ETC_PTMP);
- if (shadows != NULL) shadows->write();
- ret = 0;
- }
- return ret;
- }
-
- /*
- Select one user from the list.
- May return NULL if no valid selection was done (escape). See code.
- */
- PUBLIC USER *USERS::select(
- USER *like, // Used to select which user to pick.
- // the function USER::islike() is called for
- // each.
- int may_add, // Set the delete and add button
- MENU_STATUS &code,
- int &choice) // Will contain the selection. Not so useful
- // but help for the reentrancy of the list
- // (It reedit on the last item selected).
- {
- int nbu = getnb();
- sortbyname();
- /* #Specification: userconf / user account / root bin ...
- Some special account are simply left out of the configuration
- menu. These account are never edited. They make the list larger
- for no reason.
-
- Also account with special shells are not shown. This include
- accounts like uucp and slip. Theu are show in a separate menu.
-
- The same functionnality is used to edit those accounts, but
- the editition is trigerred from different menus.
- */
- DIALOG dia;
- for (int i=0; i<nbu; i++){
- USER *usr = getitem(i);
- if (usr->is_like(like)){
- dia.new_menuitem (usr->getname(),usr->getgecos());
- }
- }
- if (may_add){
- dia.addwhat (MSG_R(I_TOADD));
- }
- code = dia.editmenu (MSG_U(T_USERACCT,"Users accounts")
- ,may_add
- ? MSG_U(I_CANEDIT,"You can edit, add, or delete users")
- : MSG_U(I_SELECT,"You must select one of those users")
- ,help_users
- ,choice,0);
- USER *ret = NULL;
- // Locate the selected user in the list, given that not all
- // user where displayed.
- int nou = 0;
- for (int j=0; j<nbu; j++){
- USER *usr = getitem(j);
- if (usr->is_like(like)){
- if (nou == choice){
- ret = usr;
- break;
- }
- nou++;
- }
- }
- return ret;
- }
-
- /*
- Add one new user
- Return -1 if the user was not added.
- */
- PUBLIC int USERS::addone (
- USER *special,
- const char *name, // Proposed login name
- GROUPS &groups)
- {
- int ret = -1;
- USER *user = new USER;
- user->setlike (special);
- user->setname (name);
- ret = user->edit(*this,groups,1);
- if (ret==0){
- add (user);
- write ();
- }else{
- delete user;
- }
- return ret;
- }
-
- /*
- General edition (addition/deletion/correction) of /etc/passwd
- */
- PUBLIC int USERS::edit(
- USER *special) // Template for user creation
- // and selection.
- {
- int ret = -1;
- int choice = 0;
- GROUPS groups;
- while (1){
- MENU_STATUS code;
- USER *usr = select (special,1,code,choice);
- if (code == MENU_ESCAPE || code == MENU_QUIT){
- break;
- }else if (code == MENU_OK){
- if (usr != NULL){
- int status = usr->edit(*this,groups,0);
- if (status != -1){
- if (status == 1) remove_del (usr);
- write();
- ret = 0;
- }
- }
- }else if (perm_rootaccess(MSG_U(P_USERDB
- ,"to maintain the user database"))){
- if (code == MENU_ADD){
- addone (special,NULL,groups);
- }
- }
- }
- return ret;
- }
- static int cmpbyname (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2)
- {
- USER *g1 = (USER*) o1;
- USER *g2 = (USER*) o2;
- return strcmp(g1->getname(),g2->getname());
- }
- /*
- Sort the array of group by name
- */
- PUBLIC void USERS::sortbyname()
- {
- sort (cmpbyname);
- }
- static int cmpbygid (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2)
- {
- USER *g1 = (USER*) o1;
- USER *g2 = (USER*) o2;
- int ret = g1->getgid() - g2->getgid();
- if (ret == 0){
- ret = strcmp(g1->getname(),g2->getname());
- }
- return ret;
- }
- /*
- Sort the array of group by gid, and name
- */
- PUBLIC void USERS::sortbygid()
- {
- sort (cmpbygid);
- }
- /*
- Edition of users password.
- Return 0 if at least one change was done.
- */
- PUBLIC int USERS::editpass(
- USER *special) // see USERS::select()
- {
- int ret = -1;
- int choice = 0;
- while (1){
- MENU_STATUS code;
- USER *usr = select (special,0,code,choice);
- if (code == MENU_ESCAPE || code == MENU_QUIT){
- break;
- }else{
- SHADOW *shadow = getshadow (usr);
- if (usr->editpass(1,shadow) != -1){
- write();
- ret = 0;
- }
- }
- }
- return ret;
- }
-
- /*
- General edition of users account and special account
- See USERS::edit()
- */
- void users_edit(
- USER *special) // Template for a special account.
- // Or NULL.
- {
- USERS users;
- users.edit(special);
- }
-
- /*
- Add one new special user
- */
- void users_addone(
- const char *name,
- const char *group) // Which group to use or NULL.
- {
- if (perm_rootaccess(MSG_R(P_USERDB))){
- USER *special;
- if (special_init (group,special) != -1){
- USERS users;
- GROUPS groups;
- users.addone(special,name,groups);
- }
- delete special;
- }
- }
-
- /*
- Return != 0 if a user account exist.
- */
- int user_exist (const char *name)
- {
- return getpwnam(name)!=NULL;
- }
-
-
- /*
- Edit one user spec.
- If the user does not exist, ask if we want to create it.
- */
- void users_editone(
- const char *name,
- const char *group) // Group to use (or NULL) if the user
- // is created
- {
- USERS users;
- if (perm_rootaccess(MSG_R(P_USERDB))){
- USER *user = users.getitem(name);
- if (user == NULL){
- char buf[300];
- sprintf (buf,MSG_U(I_USERCREATE,"User account %s does not exist\n"
- "Do you want to create it"),name);
- if (xconf_yesno(MSG_U(Q_USERCREATE,"Account creation")
- ,buf,help_users)==MENU_YES){
- users_addone (name,group);
- }
- }else{
- GROUPS groups;
- if (user->edit(users,groups,0)!=-1) users.write();
- }
- }
- }
-
-
- #ifdef TEST
-
- int main (int argc, char *argv[])
- {
- users_edit(NULL);
- users_edit("-");
- users_edit("/usr/lib/uucp/uucico");
- }
-
- #endif
-
-
-